import { _decorator, Component, UITransform } from 'cc';
import { Game } from './Game';
import { ShapeSprite } from './ShapeSprite';
const { ccclass, property } = _decorator;

@ccclass('DropCtr')
export class DropCtr extends Component {

    gridX: number; // 初始格子坐标
    gridY: number; // 初始格子坐标
    
    // 加速度下落参数（像素/秒，像素/秒^2）
    velocity: number = 0; // 当前速度
    maxSpeed: number = 7000.0; // 最大速度上限
    acceleration: number = 80000.0; // 加速度，下落感
   
    gridSize: number = 0;
    isDroping: boolean = false;
    shapeSprite: ShapeSprite = null;

    // 全局缓存数组，避免频繁 new Array
    static _minYForCol: number[] = [];
    static _maxYForCol: number[] = [];


    onLoad() {
        this.shapeSprite = this.node.getComponent(ShapeSprite);
    }

    reset(x: number, y: number) {
        let tetris = Game.instance.tetris;
        if (tetris) {

            this.isDroping = true;
            this.shapeSprite.display = true;
            this.gridSize = tetris.gridSize;
            this.velocity = 0; // 重置速度

            // 用像素坐标作为下落的初始位置
            this.gridX = x * this.gridSize;
            this.gridY = y * this.gridSize;
            this.node.setPosition(this.gridX, this.gridY);
            // 将初始格子坐标转换为像素坐标
            this.node.getComponent(UITransform).setAnchorPoint(0,1);
        }
    }

    /**
     * update
     * 俄罗斯方块像素流沙下落主循环。
     * 算法原理：
     * 1. 预先计算主面板每列的最低有像素高度（minYForCol），和 shapeSprite 每列的最深部有像素行号（maxYForCol）。
     * 2. 对每一列，计算 shape 在该列还能下落的最大步数 dropDist = minYForCol[boardX] - (currGridY + maxYForCol[j] + 1)。
     * 3. 所有列的 dropDist 取最小值，得到 shape 整体还能下落的最大步数 maxDrop。
     * 4. 若 maxDrop>0，按 speed*dt 或 maxDrop*gridSize 取最小值平滑下落。
     * 5. 若 maxDrop<=0，直接将 shape 合并到主面板并清空 shape 数据。
     * 该算法避免逐步步进模拟，极大提升了性能，实现了像素级自然流沙下落。
     */
    update(dt: number) {

        // 获取主面板数据
        let flags = Game.instance.flags;
        let colors = Game.instance.colors;
        let tetris = Game.instance.tetris;

        if (!tetris || !this.shapeSprite || !this.isDroping) return;

        let gridSize = this.gridSize;
        let boardCols = tetris.texWidth;
        let boardRows = tetris.texHeight;

        let shapeFlags = this.shapeSprite.flags;
        let shapeCols = this.shapeSprite.texWidth;
        let shapeRows = this.shapeSprite.texHeight;

        // 提前计算 gridX 和 currGridY，避免重复计算
        let gridX = Math.floor(this.gridX / gridSize);
        let currGridY = Math.round(this.gridY / gridSize);

        // 1. 预算主面板每一列最低有像素的高度
        // 只计算 shapeSprite 覆盖范围内的列，避免全部计算
        let minYForCol = DropCtr._minYForCol;
        let startCol = Math.max(0, gridX);
        let endCol = Math.min(boardCols, gridX + shapeCols);
        
        // 只初始化需要计算的列
        for (let i = startCol; i < endCol; i++) minYForCol[i] = boardRows;
        
        // 只计算 shapeSprite 覆盖范围内的列
        for (let x = startCol; x < endCol; x++) {
            for (let y = 0; y < boardRows; y++) {
                if (flags[y][x]) {
                    minYForCol[x] = y;
                    break;
                }
            }
        }
        // 2. 预算 shapeSprite 每列的最大深度（最底部有像素的行号）
        // 只计算在主面板覆盖范围内的列，避免无效计算
        let maxYForCol = DropCtr._maxYForCol;
        
        // 清空数组，只处理需要的列
        for (let j = 0; j < shapeCols; j++) maxYForCol[j] = -1;
        
        // 只计算在主面板覆盖范围内的列
        for (let j = 0; j < shapeCols; j++) {
            let boardX = gridX + j;
            // 跳过超出主面板范围的列
            if (boardX < 0 || boardX >= boardCols) continue;
            
            // 从下往上检测，遇到第一个有像素的行号即写入
            for (let i = shapeRows - 1; i >= 0; i--) {
                if (shapeFlags[i][j]) {
                    maxYForCol[j] = i;
                    break;
                }
            }
        }
        // 3. 计算每列最大下落距离
        let maxDrop = Number.MAX_SAFE_INTEGER;

        for (let j = 0; j < shapeCols; j++) {
            let bottom = maxYForCol[j];
            if (bottom < 0) continue;
            let boardX = gridX + j;
            if (boardX < 0 || boardX >= boardCols) {
                maxDrop = 0;
                continue;
            }
            let minY = minYForCol[boardX];
            let dropDist = minY - (currGridY + bottom + 1);
            if (dropDist < maxDrop) maxDrop = dropDist;
        }

        // 4. 采用加速度模型：本帧理论位移 = v*dt + 0.5*a*dt^2
        let accelMove = this.velocity * dt + 0.5 * this.acceleration * dt * dt;
        if (accelMove < 0) accelMove = 0; // 保护
        let maxPixelDrop = maxDrop * gridSize;
        if (maxDrop > 0 && maxPixelDrop > 0) {
            let move = Math.min(maxPixelDrop, accelMove);
            this.gridY += move;
            this.node.setPosition(this.gridX, -this.gridY);
            // 本帧结束更新速度（若已触底合并将不会进入此分支）
            this.velocity = Math.min(this.velocity + this.acceleration * dt, this.maxSpeed);
            return;
        }

        // 5. 合并到主面板
        let finalGridX = Math.floor(this.gridX / gridSize);
        let finalGridY = Math.round(this.gridY / gridSize) + maxDrop;
        // finalGridX, finalGridY 即为 shape 左上角最终下放到主面板的格子坐标
        let shapeColors = this.shapeSprite.colors;
        let flowCoord = Game.instance.flowCoord;
        for (let j = 0; j < shapeCols; j++) {
            let bottom = maxYForCol[j];
            if (bottom < 0) continue;
            let currPixelY = this.gridY + bottom * gridSize;
            let currGridY = Math.round(currPixelY / gridSize);
            let boardX = finalGridX + j;
            let minY = (boardX >= 0 && boardX < boardCols) ? minYForCol[boardX] : boardRows;
            let dropDist = minY - (currGridY + 1);
            for (let i = shapeRows - 1; i >= 0; i--) {
                if (shapeFlags[i][j]) {
                    let boardY = currGridY + dropDist - (bottom - i);
                    if (boardY >= 0 && boardY < boardRows && boardX >= 0 && boardX < boardCols) {
                        colors[boardY][boardX].set(shapeColors[i][j]);
                        flags[boardY][boardX] = shapeFlags[i][j];
                        flowCoord.push([boardY,boardX]);// 标记新流沙坐标
                    }
                }
            }
        }

        this.isDroping = false;
        tetris.updateDatas(colors,0,0);
        this.shapeSprite.display = false;

        //添加分数
        let score = this.shapeSprite.score;
        let x = finalGridX+this.shapeSprite.gridsW/2;
        let y = finalGridY+this.shapeSprite.gridsH/2;
        Game.instance.addScores(score,0,x,y,this.shapeSprite.color0Idx);

    }
}


